package com.junson.client;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.CharsetUtil;
import java.net.InetSocketAddress;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.junson.client.codec.Decoder;
import com.junson.client.codec.Encoder;
import com.junson.client.handler.EchoClientHandler;
import com.junson.client.handler.NettyHeartBeatDuplexHandler;

/**
 * 代码清单 2-4 客户端的主类
 *
 * @author <a href="mailto:norman.maurer@gmail.com">Norman Maurer</a>
 */
public class EchoClient {
	private static Logger logger = LoggerFactory.getLogger(EchoClient.class);
	private final String host;
	private final int port;
	private Channel channel;
	private Bootstrap bootstrap;
	private EventLoopGroup group;
	public EchoClient(String host, int port) {
		this.host = host;
		this.port = port;
	}

	public void initClient() {

		group = new NioEventLoopGroup();
		// 创建 Bootstrap
		bootstrap = new Bootstrap();
		// 指定 EventLoopGroup 以处理客户端事件；需要适用于 NIO 的实现
		bootstrap.group(group)
				// 适用于 NIO 传输的Channel 类型
				.channel(NioSocketChannel.class)
				// 设置服务器的InetSocketAddress
				// 在创建Channel时，向 ChannelPipeline中添加一个 EchoClientHandler实例
				.handler(new ChannelInitializer<SocketChannel>() {
					@Override
					public void initChannel(SocketChannel ch) throws Exception {
						ch.pipeline().addLast(new IdleStateHandler(30, 20, 0, TimeUnit.SECONDS));
						ch.pipeline().addLast(new Encoder(CharsetUtil.UTF_8));
						ch.pipeline().addLast(new Decoder(CharsetUtil.UTF_8));
						ch.pipeline().addLast(new NettyHeartBeatDuplexHandler());
						ch.pipeline().addLast(new EchoClientHandler());
					}
				});
//        bootstrap.option(ChannelOption.SO_KEEPALIVE, true)
//        .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 60000);

		// 连接到远程节点，阻塞等待直到连接完成
		// 连接到远程主机

	}

	/**
	 * connectAndSend must after initClient
	 * @param string
	 */
	private void connectAndSend(String string) {
		ChannelFuture future = null;
		try {
			future = bootstrap.connect(new InetSocketAddress(host, port)).sync();
			future.channel().writeAndFlush(Unpooled.copiedBuffer(string, CharsetUtil.UTF_8));
			future.addListener(new ChannelFutureListener() {
				@Override
				public void operationComplete(ChannelFuture future) throws Exception {
					if (future.isSuccess()) {
						logger.debug("===>成功发送请求");
						channel = future.channel();
					} else {
						future.channel().eventLoop().schedule(new Runnable() {
							
							@Override
							public void run() {
								logger.debug("===>再次发送请求");
								connectAndSend(string);
							}
						}, 2, TimeUnit.SECONDS);
					}
					
				}
			});
			future.channel().closeFuture().sync();
		} catch (Exception e) {
			logger.error(e.getMessage());
		} finally {
			try {
				group.shutdownGracefully().sync();
				bootstrap.clone();
			} catch (InterruptedException e) {
				logger.error(e.getMessage());
			}
		}
		
	}

	public static void main(String[] args) throws Exception {
		if (args.length != 2) {
			logger.debug("Usage: " + EchoClient.class.getSimpleName() + " <host> <port>");
			return;
		}
		final String host = args[0];
		final int port = Integer.parseInt(args[1]);
		logger.debug("Usage: " + EchoClient.class.getSimpleName() + " <" + args[0] + "> <" + port + ">");
		
		String string = "一般都是将这些数据转换成自己定义的一些类型";
		EchoClient echoClient = new EchoClient(host, port);
		echoClient.initClient();
		echoClient.connectAndSend(string );
		
	}
}
